﻿namespace System.Web.UI
{
    using Extensions.Web.UI;
    using Extensions.Web.ViewModel;
    using System;
    using System.ComponentModel;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Web.UI.WebControls;

    public static class ViewModel
    {
        public static T AttributeBinding<T>(this IDataBindingsAccessor view, Control control, Type controlType, string attributeName, string attributeExpression)
        {
            Binding(new BindingArgs((Control) view, control, controlType, attributeName, attributeExpression, DescriptorType.Attribute));
            return default(T);
        }

        public static object AttributeBinding(this IDataBindingsAccessor view, Control control, Type controlType, string attributeName, string attributeExpression)
        {
            return view.AttributeBinding<object>(control, controlType, attributeName, attributeExpression);
        }

        private static void Binding(BindingArgs bindingArgs)
        {
            EventHandler handler = null;
            EventHandler handler2 = null;
            EventHandler handler3 = null;
            ViewArgs args = null;
            object notifyValue = null;
            switch (bindingArgs.DescriptorType)
            {
                case DescriptorType.Property:
                case DescriptorType.Attribute:
                    if (handler2 == null)
                    {
                        handler2 = delegate (object sender, EventArgs e) {
                            if (bindingArgs.View.Page.IsPostBack)
                            {
                                if (args == null)
                                {
                                    args = new ViewArgs(bindingArgs);
                                }
                                if (args.ViewModel != null)
                                {
                                    ViewModelArgs args1 = new ViewModelArgs(args, bindingArgs.Expression, bindingArgs.BindingType);
                                    if (args1.CanWrite)
                                    {
                                        notifyValue = bindingArgs.GetControlPropertyValue();
                                        args1.SetValue(notifyValue);
                                    }
                                    else if (args1.IsNotify)
                                    {
                                        notifyValue = bindingArgs.GetControlPropertyValue();
                                    }
                                    if (!(!bindingArgs.IsBindingVisible || bindingArgs.Control.Visible))
                                    {
                                        bindingArgs.Control.Visible = true;
                                    }
                                }
                            }
                        };
                    }
                    bindingArgs.Control.Load += handler2;
                    if (handler3 == null)
                    {
                        handler3 = delegate (object sender, EventArgs e) {
                            if (args == null)
                            {
                                args = new ViewArgs(bindingArgs);
                            }
                            if (args.ViewModel != null)
                            {
                                ViewModelArgs args1 = new ViewModelArgs(args, bindingArgs.Expression, bindingArgs.BindingType);
                                if (args1.CanRead)
                                {
                                    if (args1.Component is UserControl)
                                    {
                                        ((UserControl) args1.Component).UseModel(bindingArgs.Control);
                                    }
                                    object obj2 = args1.GetValue();
                                    bindingArgs.SetControlPropertyValue(obj2);
                                    if (((notifyValue != null) && (notifyValue is IConvertible)) && !notifyValue.Equals(obj2))
                                    {
                                        UpdatePanel panel = (UpdatePanel) UserControl.DataBoundControlHelperFindControl(bindingArgs.Control, typeof(UpdatePanel));
                                        if ((panel != null) && (panel.UpdateMode == UpdatePanelUpdateMode.Conditional))
                                        {
                                            panel.Update();
                                        }
                                    }
                                }
                            }
                        };
                    }
                    bindingArgs.Control.PreRender += handler3;
                    break;

                case DescriptorType.Event:
                    if (handler == null)
                    {
                        handler = delegate (object sender, EventArgs e) {
                            args = new ViewArgs(bindingArgs);
                            if (args.ViewModel != null)
                            {
                                MethodInfo method = args.ViewModel.GetType().GetMethod(bindingArgs.Expression, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
                                if (method != null)
                                {
                                    string str;
                                    bindingArgs.AddControlEventHandler(args.ViewModel, method, out str);
                                    UpdatePanel panel = (UpdatePanel) UserControl.DataBoundControlHelperFindControl(bindingArgs.Control, typeof(UpdatePanel));
                                    if (((panel != null) && (str != "")) && (panel.UpdateMode == UpdatePanelUpdateMode.Conditional))
                                    {
                                        AsyncPostBackTrigger trigger2;
                                        bool flag = false;
                                        foreach (UpdatePanelTrigger trigger in panel.Triggers)
                                        {
                                            if (trigger is AsyncPostBackTrigger)
                                            {
                                                trigger2 = (AsyncPostBackTrigger) trigger;
                                                if ((trigger2.ControlID == bindingArgs.Control.UniqueID) && (trigger2.EventName == str))
                                                {
                                                    flag = true;
                                                    break;
                                                }
                                            }
                                        }
                                        if (!flag)
                                        {
                                            trigger2 = new AsyncPostBackTrigger {
                                                ControlID = bindingArgs.Control.UniqueID,
                                                EventName = str
                                            };
                                            panel.Triggers.Add(trigger2);
                                        }
                                    }
                                }
                            }
                        };
                    }
                    bindingArgs.Control.Init += handler;
                    break;
            }
        }

        public static object EventBinding(this IDataBindingsAccessor view, Control control, Type controlType, string eventName, string eventExpression)
        {
            return view.EventBinding<object>(control, controlType, eventName, eventExpression);
        }

        public static T EventBinding<T>(this IDataBindingsAccessor view, Control control, Type controlType, string eventName, string eventExpression)
        {
            EventDescriptor entryEventDescriptor = MemberUtility.GetEntryEventDescriptor(controlType, eventName);
            Binding(new BindingArgs((Control) view, entryEventDescriptor, control, controlType, eventName, eventExpression, DescriptorType.Event));
            return default(T);
        }

        public static T PropertyBinding<T>(this IDataBindingsAccessor view, Control control, Type controlType, string propertyName, string propertyExpression)
        {
            PropertyDescriptor entryPropertyDescriptor = MemberUtility.GetEntryPropertyDescriptor(controlType, propertyName);
            Binding(new BindingArgs((Control) view, entryPropertyDescriptor, control, controlType, propertyName, propertyExpression, DescriptorType.Property));
            return default(T);
        }

        public static object PropertyBinding(this IDataBindingsAccessor view, Control control, Type controlType, string propertyName, string propertyExpression)
        {
            return view.PropertyBinding<object>(control, controlType, propertyName, propertyExpression);
        }

        private class BindingArgs : ExpressionArgs
        {
            private System.Web.UI.Control _control;
            private Type _controlType;
            private System.Web.UI.ViewModel.DescriptorType _descriptorType;
            private MemberDescriptor _memberDescriptor;
            private string _propertyName;
            private System.Web.UI.Control _view;

            public BindingArgs(System.Web.UI.Control view, System.Web.UI.Control control, Type controlType, string propertyName, string propertyExpression, System.Web.UI.ViewModel.DescriptorType descriptorType) : base(propertyExpression)
            {
                this._view = view;
                this._control = control;
                this._controlType = controlType;
                this._propertyName = propertyName;
                this._descriptorType = descriptorType;
            }

            public BindingArgs(System.Web.UI.Control view, MemberDescriptor memberDescriptor, System.Web.UI.Control control, Type controlType, string propertyName, string propertyExpression, System.Web.UI.ViewModel.DescriptorType descriptorType) : this(view, control, controlType, propertyName, propertyExpression, descriptorType)
            {
                this._memberDescriptor = memberDescriptor;
            }

            public void AddControlEventHandler(object viewModel, MethodInfo method, out string eventName)
            {
                EventDescriptor descriptor = (EventDescriptor) this._memberDescriptor;
                Delegate delegate2 = Delegate.CreateDelegate(descriptor.EventType, viewModel, method);
                descriptor.AddEventHandler(this._control, delegate2);
                if (this.CheckIsEventHandler(method))
                {
                    eventName = descriptor.Name;
                }
                else
                {
                    eventName = "";
                }
            }

            private bool CheckIsEventHandler(MethodInfo method)
            {
                if (method.ReturnType.ToString() != "System.Void")
                {
                    return false;
                }
                ParameterInfo[] parameters = method.GetParameters();
                if (parameters.Length != 2)
                {
                    return false;
                }
                if (!parameters[1].ParameterType.IsInstanceOfType(typeof(EventArgs)))
                {
                    return false;
                }
                return true;
            }

            public object GetControlPropertyValue()
            {
                if (this._descriptorType == System.Web.UI.ViewModel.DescriptorType.Property)
                {
                    PropertyDescriptor descriptor = (PropertyDescriptor) this._memberDescriptor;
                    return descriptor.GetValue(this._control);
                }
                return ((IAttributeAccessor) this._control).GetAttribute(this._propertyName);
            }

            public void SetControlPropertyValue(object value)
            {
                if (this._descriptorType == System.Web.UI.ViewModel.DescriptorType.Property)
                {
                    PropertyDescriptor descriptor = (PropertyDescriptor) this._memberDescriptor;
                    if (value is IConvertible)
                    {
                        descriptor.SetValue(this._control, Convert.ChangeType(value, descriptor.PropertyType));
                    }
                    else
                    {
                        descriptor.SetValue(this._control, value);
                    }
                }
                else
                {
                    ((IAttributeAccessor) this._control).SetAttribute(this._propertyName, Convert.ToString(value));
                }
            }

            public override System.Web.UI.ViewModel.BindingType BindingType
            {
                get
                {
                    if (base.BindingType == System.Web.UI.ViewModel.BindingType.Default)
                    {
                        if (base.IsBuildViewModelBase)
                        {
                            return System.Web.UI.ViewModel.BindingType.TwoWay;
                        }
                        return System.Web.UI.ViewModel.BindingType.OneWay;
                    }
                    return base.BindingType;
                }
            }

            public System.Web.UI.Control Control
            {
                get
                {
                    return this._control;
                }
            }

            public Type ControlType
            {
                get
                {
                    return this._controlType;
                }
            }

            public System.Web.UI.ViewModel.DescriptorType DescriptorType
            {
                get
                {
                    return this._descriptorType;
                }
            }

            public bool IsBindingVisible
            {
                get
                {
                    if (this._descriptorType == System.Web.UI.ViewModel.DescriptorType.Property)
                    {
                        PropertyDescriptor descriptor = (PropertyDescriptor) this._memberDescriptor;
                        return (descriptor.Name == "Visible");
                    }
                    return false;
                }
            }

            public string Name
            {
                get
                {
                    return this._propertyName;
                }
            }

            public System.Web.UI.Control View
            {
                get
                {
                    return this._view;
                }
            }
        }

        public enum BindingType
        {
            Default,
            OneWay,
            TwoWay
        }

        private enum DescriptorType
        {
            Property,
            Event,
            Attribute
        }

        private class ViewArgs
        {
            private object model;
            private object viewModel;

            public ViewArgs(System.Web.UI.ViewModel.BindingArgs bindingArgs)
            {
                if (!string.IsNullOrEmpty(bindingArgs.PropertyControlID))
                {
                    this.viewModel = UserControl.DataBoundControlHelperFindControl(bindingArgs.Control, bindingArgs.PropertyControlID);
                }
                else if (!string.IsNullOrEmpty(bindingArgs.PropertyControlType))
                {
                    this.viewModel = this.DataBoundControlHelperFindControl(bindingArgs.Control, bindingArgs.PropertyControlType);
                }
                else
                {
                    Control view;
                    if (bindingArgs.View is IView)
                    {
                        view = bindingArgs.View;
                        this.viewModel = ((IView) view).ViewModel;
                    }
                    else if (bindingArgs.Control.NamingContainer != null)
                    {
                        view = bindingArgs.Control.NamingContainer;
                        this.viewModel = view.FindControl("ViewModel");
                        if (this.viewModel == null)
                        {
                            view = bindingArgs.View;
                            this.viewModel = view.FindControl("ViewModel");
                            if (this.viewModel == null)
                            {
                                view = UserControl.DataBoundControlHelperFindControl(view, typeof(ContentPlaceHolder));
                                if (view != null)
                                {
                                    this.viewModel = view.FindControl("ViewModel");
                                }
                            }
                        }
                    }
                    else
                    {
                        this.viewModel = bindingArgs.View.FindControl("ViewModel");
                    }
                }
                this.model = (this.viewModel != null) ? ((this.viewModel is IViewModel) ? ((IViewModel) this.viewModel).Model : ((this.viewModel is Control) ? ((Control) this.viewModel).FindControl("Model") : null)) : null;
            }

            private Control DataBoundControlHelperFindControl(Control control, string containerType)
            {
                for (Control control2 = control.Parent; control2.Parent != null; control2 = control2.Parent)
                {
                    string str = control2.GetType().ToString();
                    if (str.Contains("."))
                    {
                        str = str.Substring(str.LastIndexOf(".") + 1);
                    }
                    if (str == containerType)
                    {
                        return control2;
                    }
                }
                return null;
            }

            public object Model
            {
                get
                {
                    return this.model;
                }
            }

            public object ViewModel
            {
                get
                {
                    return this.viewModel;
                }
            }
        }

        private class ViewModelArgs
        {
            private ViewModel.BindingType _bindingType;
            private object component;
            private MethodInfo method;
            private PropertyInfo property;

            public ViewModelArgs(ViewModel.ViewArgs args, string expression, ViewModel.BindingType bindingType)
            {
                this._bindingType = bindingType;
                if (this.IntoBinding(args.ViewModel, expression))
                {
                    this.component = args.ViewModel;
                }
                else if ((args.Model != null) && this.IntoBinding(args.Model, expression))
                {
                    this.component = args.Model;
                }
            }

            public object GetValue()
            {
                if (this.property != null)
                {
                    return this.property.GetValue(this.component, null);
                }
                if (this.method != null)
                {
                    return this.method.Invoke(this.component, null);
                }
                return null;
            }

            private bool IntoBinding(object component, string expression)
            {
                this.property = component.GetType().GetProperty(expression, BindingFlags.Public | BindingFlags.Instance);
                if (this.property == null)
                {
                    this.method = component.GetType().GetMethod(expression, Type.EmptyTypes);
                    if (this.method == null)
                    {
                        return false;
                    }
                }
                return true;
            }

            public void SetValue(object value)
            {
                if (value is IConvertible)
                {
                    this.property.SetValue(this.component, Convert.ChangeType(value, this.property.PropertyType), null);
                }
                else
                {
                    this.property.SetValue(this.component, value, null);
                }
            }

            public bool CanRead
            {
                get
                {
                    return (((this.property != null) && this.property.CanRead) || (this.method != null));
                }
            }

            public bool CanWrite
            {
                get
                {
                    return (((this._bindingType == ViewModel.BindingType.TwoWay) && (this.property != null)) && this.property.CanWrite);
                }
            }

            public object Component
            {
                get
                {
                    return this.component;
                }
            }

            public bool IsNotify
            {
                get
                {
                    return ((this.method != null) || (this._bindingType == ViewModel.BindingType.OneWay));
                }
            }
        }
    }
}

